#include "hal_data.h"
#include <stdio.h>

#include "oled.h"
#include "bmp.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER



fsp_err_t err = FSP_SUCCESS;
volatile bool uart_send_complete_flag = false;
void user_uart_callback (uart_callback_args_t * p_args)
{
    if(p_args->event == UART_EVENT_TX_COMPLETE)
    {
        uart_send_complete_flag = true;
    }
}

#ifdef __GNUC__                                 //串口重定向
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif


PUTCHAR_PROTOTYPE
{
        err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
        if(FSP_SUCCESS != err) __BKPT();
        while(uart_send_complete_flag == false){}
        uart_send_complete_flag = false;
        return ch;
}

int _write(int fd,char *pBuffer,int size)
{
    for(int i=0;i<size;i++)
    {
        __io_putchar(*pBuffer++);
    }
    return size;
}

/* Callback function */
i2c_master_event_t i2c_event = I2C_MASTER_EVENT_ABORTED;
uint32_t  timeout_ms = 100000;
void i2c_master_callback(i2c_master_callback_args_t *p_args)
{
    i2c_event = I2C_MASTER_EVENT_ABORTED;
    if (NULL != p_args)
    {
        /* capture callback event for validating the i2c transfer event*/
        i2c_event = p_args->event;
    }
}


static void app_peripheral_init(void)
{

    // 初始化串口 UART9
    err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
    assert(FSP_SUCCESS == err);
    // 发送初始字符串用于串口测试
    char *msg = "RA E2STUDIO";
    err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)msg, strlen(msg));
    if (FSP_SUCCESS != err) __BKPT();
    while (!uart_send_complete_flag) {}
    uart_send_complete_flag = false;
    // 打印欢迎信息
    printf("\nhello world!\r\n");
    // 初始化 I2C 控制器
    err = R_IIC_MASTER_Open(&g_i2c_master0_ctrl, &g_i2c_master0_cfg);
    assert(FSP_SUCCESS == err);


}



// OLED 屏幕启动函数：完成初始化、清屏、颜色/方向配置
static void OLED_Start(void)
{
    OLED_Init();              // 初始化 OLED 屏幕（发送初始化命令序列，设置工作模式）
    OLED_Clear();             // 清空显存（OLED_GRAM），并刷新，使屏幕全黑
    OLED_ColorTurn(0);        // 设置显示颜色模式：0 为正常显示，1 为反色显示（黑白反转）
    OLED_DisplayTurn(0);      // 设置显示方向：0 为正常方向，1 为上下翻转显示

    OLED_Clear();//清空 OLED 显存
    OLED_ShowChinese(0,0,0,16,1);//在坐标 (0,0) 显示 Hzk1[0]，即汉字“瑞”，正显
    OLED_ShowChinese(16,0,1,16,1);//在坐标 (16,0) 显示 Hzk1[1]，即汉字“萨”，正显
    OLED_ShowChinese(32,0,2,16,0);//在坐标 (32,0) 显示 Hzk1[2]，即汉字“单”，反色
    OLED_ShowChinese(48,0,3,16,0);//在坐标 (48,0) 显示 Hzk1[3]，即汉字“片”，反色
    OLED_ShowChinese(64,0,4,16,0);//在坐标 (64,0) 显示 Hzk1[4]，即汉字“机”，反色
    OLED_Refresh();//将上述通过 OLED_ShowChinese() 写入 OLED_GRAM[][] 的内容，批量发送到 OLED 屏幕显示。如果没有调用这个函数，屏幕上不会出现任何内容（即写入显存但未更新）。
    OLED_ShowString(84, 0, "RA4M2", 16, 1);//在坐标 (84,0) 显示RA4M2，字体16，正显


//    OLED_ShowNum(0, 16, 20250625, 8, 16, 1);//在坐标 (0,16) 显示20250615，长度8，字体16，正显

    OLED_Refresh();// 将 OLED_GRAM 显存内容刷新到 OLED 屏幕上，显示数字和字符串

    OLED_ShowPicture(0, 32, 117, 19, BMP3, 1);                // 在 OLED 屏幕的 (x=0, y=32) 位置显示一张宽 117、高 19 像素的图片 BMP3，正常模式显示
    OLED_Refresh();                                           // 将图片内容从缓冲区刷新到 OLED 屏幕上，真正显示出来
    R_BSP_SoftwareDelay(200, BSP_DELAY_UNITS_MILLISECONDS);  // 延时 200 毫秒
}



//RTC变量
/* rtc_time_t is an alias for the C Standard time.h struct 'tm' */
rtc_time_t set_time =
{
    .tm_sec  = 50,      /* 秒，范围从 0 到 59 */
    .tm_min  = 59,      /* 分，范围从 0 到 59 */
    .tm_hour = 23,      /* 小时，范围从 0 到 23*/
    .tm_mday = 28,      /* 一月中的第几天，范围从 1 到 31*/
    .tm_mon  = 1,       /* 月份，范围从 0 到 11*/
    .tm_year = 125,     /* 自 1900 起的年数，2025为125*/
    .tm_wday = 5,       /* 一周中的第几天，范围从 0 到 6*/
//    .tm_yday=0,       /* 一年中的第几天，范围从 0 到 365*/
//    .tm_isdst=0;      /* 夏令时*/
};

//RTC闹钟变量
rtc_alarm_time_t set_alarm_time=
{
     .time.tm_sec  = 10,      /* 秒，范围从 0 到 59 */
     .time.tm_min  = 30,      /* 分，范围从 0 到 59 */
     .time.tm_hour = 12,      /* 小时，范围从 0 到 23*/
     .time.tm_mday = 1,       /* 一月中的第几天，范围从 1 到 31*/
     .time.tm_mon  = 2,       /* 月份，范围从 0 到 11*/
     .time.tm_year = 125,     /* 自 1900 起的年数，2025为125*/
     .time.tm_wday = 6,       /* 一周中的第几天，范围从 0 到 6*/

     .sec_match        =  1,
     .min_match        =  0,
     .hour_match       =  0,
     .mday_match       =  0,
     .mon_match        =  0,
     .year_match       =  0,
     .dayofweek_match  =  0,
    };

//RTC回调函数
volatile bool rtc_flag = 0;//RTC延时1s标志位
volatile bool rtc_alarm_flag = 0;//RTC闹钟
/* Callback function */
void rtc_callback(rtc_callback_args_t *p_args)
{
    /* TODO: add your own code here */
    if(p_args->event == RTC_EVENT_PERIODIC_IRQ)
        rtc_flag=1;
    else if(p_args->event == RTC_EVENT_ALARM_IRQ)
        rtc_alarm_flag=1;
}

/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */

    // 初始化外设（如 UART、I2C、中断引脚、GPIO 等）
    app_peripheral_init();

    // 初始化 OLED,保证屏幕点亮且处于默认显示状态
    OLED_Start();

    /**********************RTC开启***************************************/
    /* Initialize the RTC module*/
    err = R_RTC_Open(&g_rtc0_ctrl, &g_rtc0_cfg);

    /* Handle any errors. This function should be defined by the user. */
    assert(FSP_SUCCESS == err);

    /* Set the RTC clock source. Can be skipped if "Set Source Clock in Open" property is enabled. */
    R_RTC_ClockSourceSet(&g_rtc0_ctrl);
    /* R_RTC_CalendarTimeSet must be called at least once to start the RTC */
    R_RTC_CalendarTimeSet(&g_rtc0_ctrl, &set_time);
    /* Set the periodic interrupt rate to 1 second */
    R_RTC_PeriodicIrqRateSet(&g_rtc0_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);

    R_RTC_CalendarAlarmSet(&g_rtc0_ctrl, &set_alarm_time);
    uint8_t rtc_second= 0;      //秒
    uint8_t rtc_minute =0;      //分
    uint8_t rtc_hour =0;         //时
    uint8_t rtc_day =0;          //日
    uint8_t rtc_month =0;      //月
    uint16_t rtc_year =0;        //年
    uint8_t rtc_week =0;        //周
    rtc_time_t get_time;


    while (1)
    {
        if(rtc_flag)
        {
            R_RTC_CalendarTimeGet(&g_rtc0_ctrl, &get_time);//获取RTC计数时间
            rtc_flag=0;
            rtc_second=get_time.tm_sec;//秒
            rtc_minute=get_time.tm_min;//分
            rtc_hour=get_time.tm_hour;//时
            rtc_day=get_time.tm_mday;//日
            rtc_month=get_time.tm_mon;//月
            rtc_year=get_time.tm_year; //年
            rtc_week=get_time.tm_wday;//周
            printf(" %d y %d m %d d %d h %d m %d s %d w\n",rtc_year+1900,rtc_month+1,rtc_day,rtc_hour,rtc_minute,rtc_second,rtc_week);

            OLED_ShowNum(0, 16, rtc_year+1900, 4, 12, 1);//在坐标 (0,16) 显示年份，长度4，字体16，正显
            OLED_ShowString(24, 16, ":" ,12, 1);//在坐标 (32,16) 显示:，字体16，正显
            OLED_ShowNum(30, 16, rtc_month+1, 2, 12, 1);//在坐标 (40,16) 显示月份，长度2，字体16，正显
            OLED_ShowString(42, 16, ":", 12, 1);//在坐标 562,16) 显示:，字体16，正显
            OLED_ShowNum(48, 16, rtc_day, 2, 12, 1);//在坐标 (64,16) 显示日，长度2，字体16，正显
            OLED_ShowString(60, 16, ":", 12, 1);//在坐标 (80,16) 显示:，字体16，正显

            OLED_ShowNum(66, 16, rtc_hour, 2, 12, 1);//在坐标 (88,16) 显示时，长度2，字体16，正显
            OLED_ShowString(78, 16, ":", 12, 1);//在坐标 (104,16) 显示:，字体16，正显

            OLED_ShowNum(84, 16, rtc_minute, 2, 12, 1);//在坐标 (88,16) 显示时，长度2，字体16，正显
            OLED_ShowString(96, 16, ":", 12, 1);//在坐标 (104,16) 显示:，字体16，正显

            OLED_ShowNum(102, 16, rtc_second, 2, 12, 1);//在坐标 (88,16) 显示时，长度2，字体16，正显
//            OLED_ShowString(120, 16, ":", 12, 1);//在坐标 (104,16) 显示:，字体16，正显

            OLED_Refresh();// 将 OLED_GRAM 显存内容刷新到 OLED 屏幕上，显示数字和字符串

            }
        if(rtc_alarm_flag)
        {
            rtc_alarm_flag=0;
            printf("/************************Alarm Clock********************************/\n");
            }
        // 软件延时 1ms，控制循环节奏（相当于每 1ms 执行一次）
        R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
    }
#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}



/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP->DFLCTL = 1U;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open (&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);

#if BSP_CFG_SDRAM_ENABLED

        /* Setup SDRAM and initialize it. Must configure pins first. */
        R_BSP_SdramInit(true);
#endif
    }
}

#if BSP_TZ_SECURE_BUILD

FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{

}
FSP_CPP_FOOTER

#endif
